#!/usr/bin/env python3

import json
import requests
import time
import logging
import logging.config
import subprocess
import datetime
import os
import os.path
import shutil
import psutil
import configparser

http_base_url = "http://127.0.0.1:7002/hk/getUrl"
zlm_base_url = "http://127.0.0.1:{}/index/api/"
secret = "dwpvtEFKmFmKrVhExklx6LRDSoVbmc2w"
zlm_process_name = "MediaServer"
zlm_process_path = "/home/tyiot/tye/zhangwan/ZLMediaKit/release/linux/Debug/MediaServer"
storage_dir = "/home/tyiot/tye/zhangwan/videos"
minimum_residual_space = 100
begin_hour = 7
end_hour = 20

device_code = [
    "11324713001310892516",
    "11324713001310936214",
    "16726073001310418203",
    "19860494001310132428",
    "34114500729239082472",
    "19585006001310620385",
    "51667200041310232139",
    "19860494001310725738",
    # "30925199853332784439",
    # "39572509622700564945",
    # "30712193417078788503",
    # "38777263292672875096",
    # "35022512393827288226"
]

device_status = {}
files_dict = {}

"""
    {
        "code": "0",
        "msg": "success",
        "data": {
            "url": "rtsp://10.2.145.66:655/EUrl/CLJ52BW"
        }
    }
"""


def set_logger():
    log_config = {
        'version': 1,
        'handlers': {
            'file_handler': {
                'class': 'logging.handlers.RotatingFileHandler',
                'filename': 'output.log',
                'mode': 'a',
                'maxBytes': 1024*1024*100,
                'backupCount': 3,
                'encoding': 'utf-8',
                'formatter': 'my_formatter'
            },
            'console_handler': {
                'class': 'logging.StreamHandler',
                'level': 'DEBUG',
                'formatter': 'my_formatter'
            }
        },
        'formatters': {
            'my_formatter': {
                'format': '%(asctime)s | %(levelname)s:  %(message)s'
            }
        },
        'root': {
            'level': 'DEBUG',
            'handlers': ['file_handler', 'console_handler']
        }
    }

    # 加载日志配置字典
    logging.config.dictConfig(log_config)


def get_rtsp_url(dev: str):
    params = {"id": dev, "streamType": "1"}
    response = requests.get(http_base_url, params=params)
    if response.status_code == 200:
        doc = json.loads(response.text)
        if doc["code"] == "0":
            return doc["data"]["url"]
    return ""


def add_pull_proxy(rtsp_url: str, device_code: str) -> bool:
    params = {
        "vhost": "__defaultVhost__",
        "secret": secret,
        "app": "proxy",
        "stream": device_code,
        "url": rtsp_url,
        "retry_count": 3,
        "timeout_sec": 10,
        "enable_mp4": True,
        "auto_close": False,
        "mp4_max_second": 60,
        "enable_hls": False,
        "enable_hls_fmp4": False,
        "enable_rtsp": False,
        "enable_rtmp": False,
        "enable_ts": False,
        "enable_fmp4": False,
        "mp4_as_player": True,
        "auto_close": False,
        "mp4_save_path": storage_dir
    }
    response = requests.get(zlm_base_url + "addStreamProxy", params=params)
    logging.info(response.text)
    if response.status_code == 200:
        doc = json.loads(response.text)
        if doc["code"] == 0:
            return True
        elif doc["code"] == -1:
            if doc["msg"] == "This stream already exists":
                return True
    return False


def del_pull_proxy(device_code: str) -> bool:
    params = {
        "vhost": "__defaultVhost__",
        "secret": secret,
        "app": "proxy",
        "stream": device_code,
        "force": True
    }
    response = requests.get(zlm_base_url + "close_streams", params=params)
    if response.status_code == 200:
        logging.info(f"删除拉流代理：{device_code}")
        return True
    return False


def get_media_list():
    params = {
        "vhost": "__defaultVhost__",
        "secret": secret,
        "schema": "rtsp",
        "app": "proxy",
    }

    # 获取数据前，先将所有状态设置为False
    for code in device_code:
        device_status[code] = False

    response = requests.get(zlm_base_url + "getMediaList", params=params)
    print(response.text)
    if response.status_code == 200:
        doc = json.loads(response.text)
        if doc["code"] == 0:
            if ("data" in doc) and (len(doc["data"]) > 0):
                for item in doc["data"]:
                    stream = str(item["stream"])
                    # logging.info(stream)
                    if stream in device_status:
                        device_status[stream] = True


def check_zlm_process():
    for process in psutil.process_iter():
        if process.name() == zlm_process_name:
            print("ZLM is running")
            break
    else:
        logging.warn("ZLM doesn't running")
        process = subprocess.Popen(
            [zlm_process_path], stdout=subprocess.PIPE, stderr=subprocess.PIPE)


def check_residual_space():
    return shutil.disk_usage(storage_dir).free / 1024.0 / 1024.0 / 1024.0


def search_files(dir: str):
    for filename in os.listdir(dir):
        filepath = os.path.join(dir, filename)
        if os.path.isfile(filepath):
            file_ext = os.path.splitext(filename)[1]
            if file_ext == ".mp4":
                timestamp = os.path.getctime(filepath)
                files_dict[filepath] = timestamp
        elif os.path.isdir(filepath):
            search_files(filepath)


def clean_storage():
    files_dict.clear()

    search_files(storage_dir)

    oldest_file = min(files_dict, key=files_dict.get)

    try:
        os.remove(oldest_file)
        logging.warn(f"删除文件：{oldest_file}")
    except Exception as e:
        logging.warn("删除文件失败：{}".format(e.__dict__))


if __name__ == "__main__":
    set_logger()

    config = configparser.ConfigParser()
    config.read("config.ini")
    secret = config.get("api", "secret")
    port = config.get("http", "port")
    zlm_base_url = zlm_base_url.format(port)

    while True:
        try:
            check_zlm_process()

            get_media_list()
            logging.info(device_status)

            now = datetime.datetime.now()
            enable_pull_proxy = False
            if now.hour < end_hour and now.hour > begin_hour:
                enable_pull_proxy = True

            for code in device_code:
                if enable_pull_proxy:
                    # 如果不存在
                    if device_status[code] == False:
                        rtsp_url = get_rtsp_url(code)
                        if len(rtsp_url) != 0:
                            add_pull_proxy(rtsp_url, code)
                        else:
                            logging.error(f"无法获取RTSP地址：{code}")
                else:
                    if device_status[code] == True:
                        del_pull_proxy(code)
            space = check_residual_space()
            if space < minimum_residual_space:
                clean_storage()

        except Exception as e:
            logging.info(e)

        time.sleep(10)
